/* Echo
   (c)2002 Trilinear
*/

#include "echo.h"


#define DEGTORAD 0.0174532f
#define RADTODEG 57.2957795f

#define UMAX 6.0f
#define VMAX 3.0f
#define SDIFF 0.003f
#define SDIF2 0.005f
#define UDIFF (1.0f/6.0f)-SDIFF
#define VDIFF (1.0f/3.0f)-SDIFF

#define STDSTART 0
#define STDEND 9
#define CLIMBSTART 10
#define CLIMBMID 20
#define CLIMBEND 29
#define JOGSTART 30
#define JOGMID 35
#define JOGEND 41
#define JUMPSTART 42
#define JUMPEND 66
#define PUSHSTART 67
#define PUSHMID 71
#define PUSHEND 76
#define DIESTART 77
#define DIEEND 92
#define FRAMEMAX 92

#define MMSTAND 0
#define MMCLIMB 1
#define MMWALK 2
#define MMJOG 3
#define MMJUMP 4
#define MMPUSH 5
#define MMDIE 6

#define GRAVITY 0.070f
#define JUMPVEL -0.40f
#define JUMPACCTIME 8
#define TERMVEL 0.9f
#define MAXVELX 0.4f
#define RUNVELX 0.4f
#define AIRFRICTION 0.9f
#define BOUNCEFRICTION 0.99f
#define CLIMBSPEED 0.2f

#define MAXINACTIVETIME 150
#define BLINKTIME 5


#define TEXCOUNT 8

typedef struct {
	vector pos;
	vector vel;
	float delta;
	int dying;
	int jumping;
	int pushing;
	int climbing;
	int canjump;
	int jumppush;
	int hitblock;
	int movemode;
	int flip;
	int level;
	int route;
	char moving;
} herotype2;



typedef struct {
	float x,y,z,rx,ry,zoom;
} mycamtype2;

herotype2 echo;
mycamtype2 cam;

vector vecE,vecG,vecR;
pgmmodel path_echo;

extern char OWshowpanel=0;
#ifdef SCREENSHOTMAKER
extern char OWtakeshot=0;
#endif

int routes[9][2]={
	{ 1,2}, //left, right up down
	{ 2,3},//2
	{ 2,4},//3
	{ 4,5},//4
	{ 4,6},//5 
	{ 6,7},//6
	{ 7,8},//7
	{ 9,10},//8
	{ 8,9},//9
};

int routepaths[10][4]={
	{1,0,0,0}, //left, right up down
	{3,-1,0,2},//2
	{0,0,-2,0},//3
	{5,-3,0,4},//4
	{0,0,-4,0},//5 
	{0,-5,0,6},//6
	{0,0,-6,7},//7
	{0,0,-7,9},//8
	{8,0,-9,0},//9
	{0,-8,0,0},//10
};


void restartoverworld() {
	vector tempVec;
	float tempangle;

	echo.pos.x = 0.0f;
	echo.pos.y = 0.0f;
	echo.pos.z = 40.0f;
	echo.vel.x=echo.vel.y=echo.vel.z = 0.0f;
	echo.dying=0;
	echo.jumping=0;
	echo.pushing=0;
	echo.climbing=0;
	echo.canjump=1;
	echo.jumppush=0;
	echo.hitblock=0;
	echo.movemode=MMSTAND;
	echo.flip=-1;
	echo.delta=0;
	echo.route=1;
	echo.moving=0;

	cam.x = 0;
	cam.z = 0;
	cam.ry = 0.0f;
	cam.zoom = 1000.0f;

	if (OWdir==1) cam.ry=FLOAT0CLIP( OWangle*RADTODEG+90 );
	if (OWdir==2) cam.ry=FLOAT0CLIP( OWangle*RADTODEG+90 );
	if (OWdir==3) cam.ry=FLOAT0CLIP( OWangle*RADTODEG+180 );
	if (OWdir==4) cam.ry=FLOAT0CLIP( OWangle*RADTODEG+180 );

	if (OWdir==0) 
	{
		if (pgm_getindex(echo.level,&echo.delta,&tempVec,&OWangle, &path_echo)!=0) 
			DBGOUT("bad line segment");
	}
	else if (pgm_getindex(echo.level,&echo.delta,&tempVec,&tempangle, &path_echo)!=0) 
	{
		DBGOUT("bad line segment");
	}
	
	SETVEC(echo.pos,tempVec.x,tempVec.y,echo.pos.z);
	SETVEC(cam,tempVec.x,tempVec.y,cam.z);

	SETVEC(vecE,echo.pos.x,echo.pos.y,echo.pos.z+10);
	SETVEC(vecG,echo.pos.x,echo.pos.y,0);
	
	if (GroundCollison(&vecE,&vecG,&vecR,&mod_ground)==1) echo.pos.z=vecR.z;

}

void resetoverworld() {

	restartoverworld();
}

void initoverworld() {
//	rtc = (vuint32*)0xa0710000;

	snd_stream_init( NULL );
    sound_jump=snd_sfx_load( ROMDISKDIR "jump.wav" );
	sound_land=snd_sfx_load( ROMDISKDIR "land.wav" );
	sound_walk=snd_sfx_load( ROMDISKDIR "walk.wav" );
	sound_bumpup=snd_sfx_load( ROMDISKDIR "bumpup.wav" );
	sound_bumpbox=snd_sfx_load( ROMDISKDIR "bumpbox.wav" );

	load_agm(ROMDISKDIR "echo.agm",&mod_echo);
	load_agm(ROMDISKDIR "sky.agm",&mod_sky);

	load_tgm(ROMDISKDIR "island.tgm",&mod_ground);

	load_pgm(ROMDISKDIR "islandpath.pgm",&path_echo);
	

	/* Load a texture */
	loadjpg(ROMDISKDIR "echo.txr", 512, &tex_echo);
	loadjpg(ROMDISKDIR "echoblink.txr", 512, &tex_echoblink);
	loadjpg(ROMDISKDIR "sky.txr", 256, &tex_sky);

	loadjpg(ROMDISKDIR "island.txr", 256, &tex_ground[0]);
	loadjpg(ROMDISKDIR "water.txr", 256, &tex_ground[1]);
	loadjpg(ROMDISKDIR "Alumox.txr", 256, &tex_ground[2]);
	loadjpg(ROMDISKDIR "button.txr", 256, &tex_ground[3]);
	loadjpg(ROMDISKDIR "wood.txr", 256, &tex_ground[4]);
	loadjpg(ROMDISKDIR "castle.txr", 256, &tex_ground[5]);
	loadjpg(ROMDISKDIR "Grass.txr", 256, &tex_ground[6]);

	loadpng(ROMDISKDIR "panel.txa",PNG_FULL_ALPHA, &tex_panel);
	inactivetime=0;
	blinkcount=0;
	resetoverworld();

	button=0;
//	oldtime = rtc[1]&0xFFFF;//timer_count(TMU0);

	c = maple_first_controller();

	button=0;
	blinkcount=0;
}

void killoverworld() {
	free_agm(&mod_echo);
	free_agm(&mod_sky);
	
	free_tgm(&mod_ground);

	free_pgm(&path_echo);
	
	snd_sfx_unload_all();
	snd_stream_shutdown();
	
	glDeleteTextures(1, &tex_echo);
	glDeleteTextures(1, &tex_echoblink);
	glDeleteTextures(1, &tex_sky);
	glDeleteTextures(1, &tex_ground[0]);
	glDeleteTextures(1, &tex_ground[1]);
	glDeleteTextures(1, &tex_ground[2]);
	glDeleteTextures(1, &tex_ground[3]);
	glDeleteTextures(1, &tex_ground[4]);
	glDeleteTextures(1, &tex_ground[5]);
	glDeleteTextures(1, &tex_ground[6]);
	glDeleteTextures(1, &tex_panel);
}






void OWDrawScene() {
	int i;
		/* Begin frame */
	glKosBeginFrame();

	glLoadIdentity();

	glPushMatrix();

		glRotatef(-90, 1.0f, 0.0f, 0.0f);
		glTranslatef(0, cam.zoom, -30);

		glRotatef(cam.rx+28, 1.0f, 0.0f, 0.0f);
		glRotatef(cam.ry, 0.0f, 0.0f, 1.0f);

		glPushMatrix();
			glScalef(0.5f, 0.5f, 0.5f);
			glRotatef(90, 0.0f, 0.0f, 1.0f);
			glBindTexture( GL_TEXTURE_2D, tex_sky);
			CommonTexParams();
			draw_agm(&mod_sky);
		glPopMatrix();
	
		glTranslatef(-cam.x, -cam.y , -cam.z);

		glPushMatrix();
//			glEnable(GL_KOS_VFZ_CLIPPING);
			draw_tgm_byID(&mod_ground,(uint32*)tex_ground,-1,TEXCOUNT);
			for (i=0;i<10;i++) {
				if (levelcompleted[i]==1) glColor3f(0,0,0.7f); 
				else if (levelcompleted[i]==0) glColor3f(0.7f,0,0); else glColor3f(0.2f,0.2f,0.2f); 
				draw_tgm_byID(&mod_ground,(uint32*)tex_ground,i+1,TEXCOUNT);
			}
			glColor3f(1.0f,1.0f,1.0f);
//			glDisable(GL_KOS_VFZ_CLIPPING);
//			drawfloor((int)cam.x);
		glPopMatrix();
	

		glDisable(GL_CULL_FACE);
		glPushMatrix();
			glTranslatef(echo.pos.x, echo.pos.y,echo.pos.z);
			glScalef(1.5f, 1.5f, 1.5f);
			glRotatef(-OWangle*RADTODEG+echo.flip*90-90, 0.0f, 0.0f, 1.0f);
			if (blinkcount<0) {
				if (blinkcount<-BLINKTIME) blinkcount=rand()%100;
				blinkcount--;
				glBindTexture( GL_TEXTURE_2D, tex_echoblink);
			}else{
				glBindTexture( GL_TEXTURE_2D, tex_echo);
				blinkcount--;
			}
			CommonTexParams();
			draw_agm(&mod_echo);
		glPopMatrix();

	
	glPopMatrix();


	glKosFinishList(); 

	if (OWshowpanel) {
		glBindTexture( GL_TEXTURE_2D, tex_panel);
		CommonTexParams();
		DrawPanel(score,lives);
	}

	/* Finish the frame */
	glKosFinishFrame();
}



//return 0-normal  1-restart level 2-next level 3-quit
int OWCheckInput() {
	vector tempVec;
	int climbdir=1;
	int destination;

	echo.movemode=MMSTAND;
	if (cont_get_cond(c, &cond) < 0) {
		DBGOUT("Error reading controller\n");
		return 3;
	}
	
	if (!(cond.buttons & CONT_START) && !(cond.buttons & CONT_Y))
		return 3;
	if (!(cond.buttons & CONT_START)) {
		if (Menu()==2) return 3;
	}


#ifdef SCREENSHOTMAKER
	if (!(cond.buttons & CONT_X)) {
		if (button==0) OWtakeshot=1;
		button=1;
	}else{
		button=0;
	}
#endif

	if (echo.moving!=0) {
		if (pgm_getindex(echo.route,&echo.delta,&tempVec,&OWangle, &path_echo)!=0) 
			DBGOUT("bad line segment");
		SETVEC(echo.pos,tempVec.x,tempVec.y,echo.pos.z);
		SETVEC(cam,tempVec.x,tempVec.y,cam.z);

		SETVEC(vecE,echo.pos.x,echo.pos.y,echo.pos.z+10);
		SETVEC(vecG,echo.pos.x,echo.pos.y,0);

		if (GroundCollison(&vecE,&vecG,&vecR,&mod_ground)==1) echo.pos.z=vecR.z;
		if (echo.flip==1) echo.delta-=0.01f;
		if (echo.flip==-1) echo.delta+=0.01f;
		echo.movemode=MMJOG;
		if (echo.delta>1) {
			echo.level=routes[echo.route-1][1];
			echo.moving=0;echo.delta=0;
		}
		if (echo.delta<0) {
			echo.level=routes[echo.route-1][0];
			echo.moving=0;echo.delta=0;
		}
	
	}
	if (OWdir==1) cam.ry=FLOAT0CLIP( OWangle*RADTODEG+90 );
	if (OWdir==2) cam.ry=FLOAT0CLIP( OWangle*RADTODEG+90 );
	if (OWdir==3) cam.ry=FLOAT0CLIP( OWangle*RADTODEG+180 );
	if (OWdir==4) cam.ry=FLOAT0CLIP( OWangle*RADTODEG+180 );

	if (!(cond.buttons & CONT_DPAD_UP)) {
		if (routepaths[echo.level-1][2]!=0 && echo.moving==0) {
			if (routepaths[echo.level-1][2]>0) destination=routes[routepaths[echo.level-1][2]-1][1];
			else destination=routes[-routepaths[echo.level-1][2]-1][0];
			if (levelcompleted[destination-1]!=0 || levelcompleted[echo.level-1]!=0 || OWunlock) {
				OWdir=3;
				if (routepaths[echo.level-1][2]>0) echo.flip=-1;
				else {echo.flip=1;echo.delta=1;}
				echo.movemode=MMJOG;
				echo.route=abs(routepaths[echo.level-1][2]);
				echo.moving=1;
			}
		}
	}else if (!(cond.buttons & CONT_DPAD_DOWN)) {
		if (routepaths[echo.level-1][3]!=0 && echo.moving==0) {
			if (routepaths[echo.level-1][3]>0) destination=routes[routepaths[echo.level-1][3]-1][1];
			else destination=routes[-routepaths[echo.level-1][3]-1][0];
			if (levelcompleted[destination-1]!=0 || levelcompleted[echo.level-1]!=0 || OWunlock) {
				OWdir=4;
				if (routepaths[echo.level-1][3]>0) echo.flip=-1;
				else {echo.flip=1;echo.delta=1;}
				echo.movemode=MMJOG;
				echo.route=abs(routepaths[echo.level-1][3]);
				echo.moving=1;
			}
		}
	}
	if (!(cond.buttons & CONT_DPAD_LEFT)) {
		if (routepaths[echo.level-1][0]!=0 && echo.moving==0) {
			if (routepaths[echo.level-1][0]>0) destination=routes[routepaths[echo.level-1][0]-1][1];
			else destination=routes[-routepaths[echo.level-1][1]-1][0];
			if (levelcompleted[destination-1]!=0 || levelcompleted[echo.level-1]!=0 || OWunlock) {
				OWdir=1;
				if (routepaths[echo.level-1][0]>0) echo.flip=-1;
				else {echo.flip=1;echo.delta=1;}
				echo.movemode=MMJOG;
				echo.route=abs(routepaths[echo.level-1][0]);
				echo.moving=1;
			}
		}
	}else if (!(cond.buttons & CONT_DPAD_RIGHT)) {
		if (routepaths[echo.level-1][1]!=0 && echo.moving==0) {
			if (routepaths[echo.level-1][1]>0) destination=routes[routepaths[echo.level-1][1]-1][1];
			else destination=routes[-routepaths[echo.level-1][1]-1][0];
			if (levelcompleted[destination-1]!=0 || levelcompleted[echo.level-1]!=0 || OWunlock) {
				OWdir=2;
				if (routepaths[echo.level-1][1]>0) echo.flip=-1;
				else {echo.flip=1;echo.delta=1;}
				echo.movemode=MMJOG;
				echo.route=abs(routepaths[echo.level-1][1]);
				echo.moving=1;
			}
		}
	}
	if (!(cond.buttons & CONT_A) && echo.moving==0) {
		if (levelcompleted[echo.level-1]!=2 && echo.level>1) return 1;
	}


//	cam.ry+=(((float)cond.joyx)-128)/50;
	cam.rx=(((float)cond.joyy)-128)/7;
//	cam.rx+=(((float)cond.joyy)-128)/50;
	cam.zoom=FLOAT0CLIP( ( (10*cam.zoom+ (300-((float)cond.rtrig)/4) )*(1.0f/11.0f)) );



	if (echo.movemode!=MMCLIMB) {
		mod_echo.curFrame+=1;
	}

	if (echo.movemode==MMSTAND) {
		if (mod_echo.curFrame>STDEND) mod_echo.curFrame=STDSTART;
		if (mod_echo.curFrame<STDSTART) mod_echo.curFrame=STDSTART;
	}else if (echo.movemode==MMJOG) {
		if (mod_echo.curFrame>JOGEND) mod_echo.curFrame=JOGSTART;
		if (mod_echo.curFrame<JOGSTART) mod_echo.curFrame=JOGSTART;

		if (mod_echo.curFrame==JOGSTART) snd_sfx_play(sound_walk, 140, 128 );
		if (mod_echo.curFrame==JOGMID) snd_sfx_play(sound_walk, 140, 128 );
	}else if (echo.movemode==MMPUSH) {
		if (mod_echo.curFrame>PUSHEND) mod_echo.curFrame=PUSHSTART;
		if (mod_echo.curFrame<PUSHSTART) mod_echo.curFrame=PUSHSTART;

		if (mod_echo.curFrame==PUSHSTART) snd_sfx_play(sound_walk, 140, 128 );
		if (mod_echo.curFrame==PUSHMID) snd_sfx_play(sound_walk, 140, 128 );
	}else if (echo.movemode==MMJUMP) {
		if (mod_echo.curFrame>JUMPEND) mod_echo.curFrame=JUMPEND;
		if (mod_echo.curFrame<JUMPSTART) mod_echo.curFrame=JUMPSTART;
	}else if (echo.movemode==MMCLIMB) {
		if (mod_echo.curFrame>CLIMBEND) mod_echo.curFrame=CLIMBSTART;
		if (mod_echo.curFrame<CLIMBSTART) mod_echo.curFrame=CLIMBEND;
		if (mod_echo.curFrame>=CLIMBSTART && mod_echo.curFrame<=CLIMBSTART+1.0f && climbdir!=0) snd_sfx_play(sound_walk, 140, 128 );
		if (mod_echo.curFrame>=CLIMBMID && mod_echo.curFrame<=CLIMBMID+1.0f && climbdir!=0) snd_sfx_play(sound_walk, 140, 128 );
	}else  if (echo.movemode==MMDIE) {
		if (mod_echo.curFrame>DIEEND) {
			mod_echo.curFrame=DIEEND;
			restartoverworld();
		}
		if (mod_echo.curFrame<DIESTART) mod_echo.curFrame=DIESTART;
	}
	UpdateAnim(&mod_echo);



	return 0;
}


int runoverworld(int* level, int *life,int *scores) {
	int timediff=0,In,framecount=0;

	struct timeval tvoldtime,tvnewtime;
	struct timezone newtimezone;

	gettimeofday(&tvoldtime, &newtimezone);
	gettimeofday(&tvnewtime, &newtimezone);

	lives=*life;
	score=*scores;
	echo.level=*level+1;
	initoverworld();
	In=0;
	while(1) {
		/* Check key status */
		if (SystemUpdate()) {In=3;break;}

		In=OWCheckInput();
		if (In!=0) break;

		//delay state change by one frame
		
/*		curtime = rtc[1]&0xFFFF;//timer_count(TMU0);
		if (curtime!=oldtime) {
			DBGOUT("%d\r\n",(int)framecount);
			framecount=0;

		}
		oldtime=curtime;
*/		framecount++;

		OWDrawScene();
		#ifdef SCREENSHOTMAKER
		if (OWtakeshot) {
			vid_screen_shot("/pc/capture.ppm");
			OWtakeshot=0;
		}
		#endif

		gettimeofday(&tvnewtime, &newtimezone);
		timediff=(tvnewtime.tv_usec/1000) -(tvoldtime.tv_usec/1000);
		if (timediff<0) timediff+=1000;
		while ((timediff)<30) {
			if (SystemUpdate()) {In=3;killoverworld();return 3;}
			gettimeofday(&tvnewtime, &newtimezone);
			timediff=(tvnewtime.tv_usec/1000) -(tvoldtime.tv_usec/1000);
			if (timediff<0) timediff+=1000;
		}
		tvoldtime.tv_sec=tvnewtime.tv_sec;
		tvoldtime.tv_usec=tvnewtime.tv_usec;

	}
//	sndoggvorbis_stop();
  //  sndoggvorbis_shutdown();

	killoverworld();

	*life=lives;
	*scores=score;
	*level=echo.level-1;

	return In;

}


